using System.Collections.Generic;
using TestCases.CompareAssert.Core.Comparers.Interfaces;
using TestCases.CompareAssert.Core.Factories;
using TestCases.CompareAssert.Core.Interfaces;

namespace TestCases.CompareAssert.Core.Comparers
{
    public static class ComparerUtils
    {
        public static IResultBuilder CompareAndAddResult(this IObjectComparer childComparer, ICompareContext context, IList<IResultProvider> results)
        {
            var childResult = childComparer.Compare(context);
            results.Add(childResult);
            return childResult;
        }

        public static IResultBuilder IsStatusResult(this IObjectComparer comparer, CompareStatus status, ICompareContext context)
        {
            return context.Factory.ForSimpleResult(comparer, status, context);
        }

        public static IResultBuilder IsEquals(this IObjectComparer comparer, ICompareContext context)
        {
            return IsStatusResult(comparer, CompareStatus.Equals, context);
        }

        public static IResultBuilder IsNotEquals(this IObjectComparer comparer, ICompareContext context)
        {
            return IsStatusResult(comparer, CompareStatus.NotEquals, context);
        }

        public static IResultBuilder IsNotApplicable(this IObjectComparer comparer, ICompareContext context)
        {
            return IsStatusResult(comparer, CompareStatus.NotApplicable, context);
        }


        public static IResultBuilder IsStatusResult(this IObjectComparer comparer, CompareStatus status, ICompareContext context,
            IResultProvider child)
        {
            return context.Factory.ForDecoratorResult(comparer, status, context, child);
        }

        public static IResultBuilder IsEquals(this IObjectComparer comparer, ICompareContext context, IResultProvider child)
        {
            return IsStatusResult(comparer, CompareStatus.Equals, context, child);
        }

        public static IResultBuilder IsNotEquals(this IObjectComparer comparer, ICompareContext context, IResultProvider child)
        {
            return IsStatusResult(comparer, CompareStatus.NotEquals, context, child);
        }

        public static IResultBuilder IsNotApplicable(this IObjectComparer comparer, ICompareContext context, IResultProvider child)
        {
            return IsStatusResult(comparer, CompareStatus.NotApplicable, context, child);
        }


        public static IResultBuilder IsStatusResult<T>(this IObjectComparer comparer, CompareStatus status, ICompareContext context,
            IList<T> children) where T: IResultProvider
        {
            return context.Factory.ForCompositeResult(comparer, status, context, children);
        }

        public static IResultBuilder IsEquals<T>(this IObjectComparer comparer, ICompareContext context, IList<T> children) where T: IResultProvider
        {
            return IsStatusResult(comparer, CompareStatus.Equals, context, children);
        }

        public static IResultBuilder IsNotEquals<T>(this IObjectComparer comparer, ICompareContext context, IList<T> children) where T: IResultProvider
        {
            return IsStatusResult(comparer, CompareStatus.NotEquals, context, children);
        }

        public static IResultBuilder IsNotApplicable<T>(this IObjectComparer comparer, ICompareContext context, IList<T> children) where T: IResultProvider
        {
            return IsStatusResult(comparer, CompareStatus.NotApplicable, context, children);
        }


        public static IResultBuilder IsBoolResult(this IObjectComparer comparer, bool expression, ICompareContext context)
        {
            return IsStatusResult(comparer, StatusUtils.FromBool(expression), context);
        }

        public static IResultBuilder IsBoolResult(this IObjectComparer comparer, bool expression, ICompareContext context, IResultProvider child)
        {
            return IsStatusResult(comparer, StatusUtils.FromBool(expression), context, child);
        }

        public static IResultBuilder IsBoolResult(this IObjectComparer comparer, bool expression, ICompareContext context,
            IList<IResultProvider> children)
        {
            return IsStatusResult(comparer, StatusUtils.FromBool(expression), context, children);
        }

        public static IResultBuilder IsResult(this IObjectComparer comparer, ICompareContext context, IResultProvider child)
        {
            return context.Factory.ForDecoratorResult(comparer, child.GetStatus(), context, child);
        }

        public static IResultBuilder IsComparerResult(this IObjectComparer comparer, ICompareContext context, IObjectComparer childComparer)
        {
            return IsResult(comparer, context, childComparer.Compare(context));
        }
                
        public static IResultBuilder IsSameAs(this IObjectComparer comparer, IResultSettings settings, ICompareContext context)
        {
            return IsStatusResult(comparer, settings.GetStatus(), context).Message(settings.GetMessage()).With(settings.GetArgs());
        }

        public static IResultBuilder IsSameAs(this IObjectComparer comparer, IResultSettings settings, ICompareContext context, IResultBuilder child)
        {
            return IsStatusResult(comparer, settings.GetStatus(), context, child).Message(settings.GetMessage()).With(settings.GetArgs());
        }
        
        public static IResultBuilder IsSameAs<T>(this IObjectComparer comparer, IResultSettings settings, ICompareContext context, IList<T> children) where T: IResultProvider
        {
            return IsStatusResult(comparer, settings.GetStatus(), context, children).Message(settings.GetMessage()).With(settings.GetArgs());
        }

        public static ICompareResult Compare(this IObjectComparer comparer, IResultBuilderFactory factory, object obj1, object obj2)
        {
            return comparer.Compare(new CompareContext(factory,
                ComparerObject.RootObject(obj1, "obj1"),
                ComparerObject.RootObject(obj2, "obj2"))).GetResult();
        }
        
        public static ICompareResult Compare(this IObjectComparer comparer, object obj1, object obj2)
        {
            return Compare(comparer, SimpleBuilderFactory.Instance, obj1, obj2);
        }
        
        public static ICompareResult CompareFull(this IObjectComparer comparer, object obj1, object obj2)
        {
            return Compare(comparer, FullBuilderFactory.Instance, obj1, obj2);
        }
        
    }
}